package com.richard.library.basic.task;

import android.text.TextUtils;

import com.richard.library.basic.util.ObjectUtil;
import com.richard.library.basic.util.ThreadPoolUtil;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Future;

/**
 * @author: Richard
 * @createDate: 2024/1/30 15:43
 * @version: 1.0
 * @description: 定时任务
 */
public final class TimerTask {

    private final ConcurrentMap<Task, Future<?>> taskManager = new ConcurrentHashMap<>();


    private static final class InstanceHolder {
        static final TimerTask instance = new TimerTask();
    }

    public static TimerTask get() {
        return InstanceHolder.instance;
    }

    private TimerTask() {
    }

    /**
     * 添加任务
     *
     * @param task 任务
     */
    public synchronized void addTask(Task task) {
        if (task == null || task.getEvent() == null) {
            return;
        }

        Future<?> value = taskManager.get(task);
        if (value != null) {
            return;
        }

        Future<?> future = this.getProcessTaskFuture(task);

        if (future == null) {
            future = this.getFuture(task);
        }

        if (future == null) {
            return;
        }

        taskManager.put(task, future);
    }

    /**
     * 停止全部定时任务
     */
    public synchronized void stop() {
        Set<Map.Entry<Task, Future<?>>> entrySet = taskManager.entrySet();

        for (Map.Entry<Task, Future<?>> item : entrySet) {
            if (item.getValue().isDone() || item.getValue().isCancelled()) {
                continue;
            }

            try {
                item.getValue().cancel(true);
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }

        taskManager.clear();
    }

    /**
     * 停止指定任务
     */
    public synchronized void stop(Task task) {
        if (task == null) {
            return;
        }

        Future<?> future = taskManager.get(task);

        if (future == null) {
            return;
        }

        future.cancel(true);
        taskManager.remove(task);
    }

    /**
     * 根据任务tag标识验证任务是否已存在
     *
     * @param tag 任务tag
     */
    public boolean isExists(String tag) {
        if (TextUtils.isEmpty(tag)) {
            return false;
        }

        Set<Map.Entry<Task, Future<?>>> entrySet = taskManager.entrySet();
        for (Map.Entry<Task, Future<?>> item : entrySet) {
            if (tag.equals(item.getKey().getTag())) {
                return true;
            }
        }

        return false;
    }

    /**
     * 验证任务是否已存在
     */
    public boolean isExists(Task task) {
        if (task == null) {
            return false;
        }
        return taskManager.containsKey(task);
    }

    /**
     * 获取普通任务事件体Future
     */
    private Future<?> getFuture(Task task) {
        if (task.getInitialDelay() == null && task.getPeriod() == null) {
            return ThreadPoolUtil.getInstance().submit(task.getEvent());
        }

        if (task.getPeriod() != null) {
            return ThreadPoolUtil.getInstance().scheduleWithFixedRate(
                    ObjectUtil.getOrDefault(task.getInitialDelay(), 0L)
                    , task.getPeriod()
                    , task.getTimeUnit()
                    , task.getEvent()
            );
        }

        return ThreadPoolUtil.getInstance().schedule(
                task.getInitialDelay()
                , task.getTimeUnit()
                , task.getEvent()
        );
    }

    /**
     * 获取自定processTask Future
     */
    private Future<?> getProcessTaskFuture(Task task) {
        ProcessTask<?> processTask = null;

        if (task.getEvent() instanceof ProcessTask) {
            processTask = (ProcessTask<?>) task.getEvent();
        }

        if (processTask == null) {
            return null;
        }

        if (task.getInitialDelay() == null && task.getPeriod() == null) {
            processTask = (ProcessTask<?>) task.getEvent();
            processTask.tryStart();
        } else if (task.getPeriod() != null) {
            processTask = (ProcessTask<?>) task.getEvent();
            processTask.tryStart(
                    ObjectUtil.getOrDefault(task.getInitialDelay(), 0L)
                    , task.getPeriod()
                    , task.getTimeUnit()
            );
        } else if (task.getInitialDelay() != null) {
            processTask = (ProcessTask<?>) task.getEvent();
            processTask.tryStart(task.getInitialDelay(), task.getTimeUnit());
        }

        return processTask.getTask();
    }
}
